package com.fengye.security.security.filter;

import com.fengye.security.config.AppProperties;
import com.fengye.security.utils.CollectionUtil;
import com.fengye.security.utils.JwtUtil;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
public class JwtFilter extends OncePerRequestFilter {
    private final AppProperties appProperties;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (checkValidJwtHeader(request)) {
            validToken(request).filter(claims -> claims.get("authorities") != null)
                    .ifPresentOrElse(this::setSecurityContext, SecurityContextHolder::clearContext);
        }
        filterChain.doFilter(request, response);
    }

    /**
     * jwtToken正确的前提下,里面jwt的自包含特性,构建Authentication,放入SecurityContext中
     * @param claims jwt对象
     */
    private void setSecurityContext(Claims claims) {
        String username = claims.getSubject();
        List<?> rawList = CollectionUtil.objectConvertToList(claims.get("authorities"));
        List<SimpleGrantedAuthority> simpleGrantedAuthorities = rawList.stream().map(String::valueOf).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, null, simpleGrantedAuthorities);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    }

    /**
     * 效验request头部是否有jwtToken
     * @param request {@link HttpServletRequest}
     * @return 效验结果
     */
    private boolean checkValidJwtHeader(HttpServletRequest request) {
        String header = request.getHeader(appProperties.getJwt().getHeader());
        return header != null && header.startsWith(appProperties.getJwt().getPrefix());
    }


    /**
     * 效验jwtToken是否合法
     * @param request {@link HttpServletRequest}
     * @return Optional对象
     */
    private Optional<Claims> validToken(HttpServletRequest request) {
        String jwtToken = request.getHeader(appProperties.getJwt().getHeader()).replace(appProperties.getJwt().getPrefix(), "");
        log.debug("token = {}", jwtToken);
        try {
            return Optional.of(Jwts.parserBuilder().setSigningKey(JwtUtil.accessTokenKey).build().parseClaimsJws(jwtToken).getBody());
        } catch (ExpiredJwtException | SignatureException | MalformedJwtException | UnsupportedJwtException |
                 IllegalArgumentException e) {
            return Optional.empty();
        }


    }
}
